--[[
命令如下
    lua asbin_2ocdtcl.lua PRJ_master.bin >out.tcl

然后在openocd脚本中添加 source out.tcl
]]

local file = io.open(arg[1],"rb");
assert(file,"error file:"..tostring(arg[1]));
local bin = file:read('*a');
local len = #bin;

local _write_pos = write_pos or 0;

local MSB = {};
for i=0,0xff do
    MSB[i] = 
        (((i>>7)&1) << 0) |
        (((i>>6)&1) << 1) |
        (((i>>5)&1) << 2) |
        (((i>>4)&1) << 3) |
        (((i>>3)&1) << 4) |
        (((i>>2)&1) << 5) |
        (((i>>1)&1) << 6) |
        (((i>>0)&1) << 7) ;
end

local read_u8 = function(offset)
    if(offset>=len)then return 0; end
    return bin:byte(offset+1);
end

local read_u16 = function(offset)
    return read_u8(offset)+read_u8(offset+1)*0x100;
end

local read_u32 = function(offset)
    return read_u16(offset)+read_u16(offset+2)*0x10000;
end

local read_u8_MSB = function(offset)
    return MSB[read_u8(offset)];
end

local read_u16_MSB = function(offset)
    return read_u8_MSB(offset)+read_u8_MSB(offset+1)*0x100;
end

local read_u32_MSB = function(offset)
    return read_u16_MSB(offset)+read_u16_MSB(offset+2)*0x10000;
end


local format = string.format;
--设置开始编程的地址
local tcl_str = 'sflash_program_begin 0x%08x';
local cur_pos = 0;
local is_end = true;

print([[set old_debug_level [debug_level] ;set e "";set old_debug_level [regsub ":" $old_debug_level $e]; debug_level 0; ]]);

--页编程
local cur_pos = 0;
if(true)then
    local pos = 0;

    while(pos<len-0x100)do
        local page = '';
        local page64 = '';
        local cc = '';
        for i=0,0xFC,4 do
            local v = read_u32_MSB(pos+i);
            if((i%64)==0 and (i~=0))then
                page64 = '0x'..page64;
                page = string.format('%s%s%s',page,cc,page64);
                cc = ' ';
                page64 = ' ';
            end
            page64 = string.format('%08x%s',v,page64);
        end
        page64 = '0x'..page64;
        page = string.format('%s%s%s',page,cc,page64);

        if((pos%1024)==0)then
            print(format('puts "%d KB"',math.floor(pos/1024)));
        end
        --print(format('sflash_erase 0x%08x',pos));
        local out = format('sflash_program_page 0x%08x %s',pos,page);
        print(out);
        --每页
        pos = pos + 0x100;
    end
    cur_pos = pos;
end

--字编程
for pos=cur_pos,len-1,4 do

    if((pos%1024)==0)then
        print(format('puts "%d kbytes"',pos/1024));
    end

    if((pos%0x100)==0)then
        --需要页对齐.一般是0x100个字节
        local s = format(tcl_str,pos + _write_pos);
        print(format('sflash_erase 0x%08x',pos + _write_pos));
        print(s);
    end

    local tcl_s = 'sflash_send32 0x%08X'
    is_end = false;
    if((pos%0x100)==(0x100-4))then
        --最后一个字节
        tcl_s = 'sflash_program_end 0x%08X'
        is_end = true;
    end
    local s = format(tcl_s,read_u32(pos));
    print(s);
end

if (not is_end)then
    print('sflash_program_end 0xffffffff');
end

print([[eval $old_debug_level]])
print('puts "flash program done!"');
